package cn.iocoder.yudao.module.product.service.spu;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.currency.api.rate.ExchangeRateApi;
import cn.iocoder.yudao.module.product.constant.ProductConstant;
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueSaveReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppDenominationVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageLikeNameReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDenominationDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.SkuDiscountDTO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.product.enums.property.PropertyValueTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductSkuStatusEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import cn.iocoder.yudao.module.product.service.brand.ProductBrandService;
import cn.iocoder.yudao.module.product.service.category.ProductCategoryService;
import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationActivityApi;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationProductDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationSkuPriceDTO;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.CATEGORY_LEVEL;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;

/**
 * 商品 SPU Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class ProductSpuServiceImpl implements ProductSpuService {

    @Resource
    private ProductSpuMapper productSpuMapper;

    @Resource
    @Lazy // 循环依赖，避免报错
    private ProductSkuService productSkuService;
    @Resource
    private ProductBrandService brandService;
    @Resource
    private ProductCategoryService categoryService;
    @Resource
    private ProductPropertyValueService productPropertyValueService;
    @Resource
    private ExchangeRateApi exchangeRateApi;
    @Resource
    private CombinationActivityApi combinationActivityApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createSpu(ProductSpuSaveReqVO createReqVO) {
        // 校验分类、品牌
        validateCategory(createReqVO.getCategoryId());
        brandService.validateProductBrand(createReqVO.getBrandId());

        // 校验 SKU
        List<ProductSkuSaveReqVO> skuSaveReqList = createReqVO.getSkus();
        productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());

        ProductSpuDO spu = BeanUtils.toBean(createReqVO, ProductSpuDO.class);

        // 初始化 SPU 中 SKU 相关属性
        initSpuFromSkus(spu, skuSaveReqList, true);

        // 插入 SPU
        productSpuMapper.insert(spu);

        // 插入 SKU
        productSkuService.createSkuList(spu.getId(), skuSaveReqList);

        // 返回
        Long spuId = spu.getId();

        // 插入属性值
        insertPropertyValue(spuId, createReqVO);

        return spuId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpu(ProductSpuSaveReqVO updateReqVO) {
        // 校验 SPU 是否存在
        validateSpuExists(updateReqVO.getId());

        // 校验分类、品牌
        validateCategory(updateReqVO.getCategoryId());
        brandService.validateProductBrand(updateReqVO.getBrandId());

        // 校验SKU
        List<ProductSkuSaveReqVO> skuSaveReqList = updateReqVO.getSkus();
        productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());

        // 更新 SPU
        ProductSpuDO updateObj = BeanUtils.toBean(updateReqVO, ProductSpuDO.class);
        initSpuFromSkus(updateObj, skuSaveReqList, false);

        productSpuMapper.updateById(updateObj);

        // 批量更新 SKU
        productSkuService.updateSkuList(updateObj.getId(), skuSaveReqList);

        // 插入属性值
        insertPropertyValue(updateReqVO.getId(), updateReqVO);
    }

    /**
     * 基于 SKU 的信息，初始化 SPU 的信息
     * 主要是计数相关的字段，例如说市场价、最大最小价、库存等等
     *
     * @param spu  商品 SPU
     * @param skus 商品 SKU 数组
     */
    private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuSaveReqVO> skus, boolean insert) {
        if (insert) {
            spu.setStatus(ProductSpuStatusEnum.DISABLE.getStatus()); // 默认状态为下架
            spu.setSalesCount(0); // 默认商品销量
            spu.setBrowseCount(0); // 默认商品浏览量
        }

        if (CollUtil.isEmpty(skus)) {
            return;
        }

        // sku 单价最低的商品的价格
        spu.setPrice(getMinValue(skus, ProductSkuSaveReqVO::getPrice));
        // sku 单价最低的商品的市场价格
        spu.setMarketPrice(getMinValue(skus.stream().filter(v -> v.getMarketPrice() != null).collect(Collectors.toList()),
                ProductSkuSaveReqVO::getMarketPrice));
        // sku 单价最低的商品的成本价格
        spu.setCostPrice(getMinValue(skus.stream().filter(v -> v.getCostPrice() != null).collect(Collectors.toList()), ProductSkuSaveReqVO::getCostPrice));
        // skus 库存总数
        spu.setStock(getSumValue(skus, ProductSkuSaveReqVO::getStock, Integer::sum));
        if (spu.getStock() > ProductConstant.STOCK_MAX) {
            spu.setStock(ProductConstant.STOCK_MAX);
        }
    }

    @Override
    public void initSpuFromSkus(Long spuId) {
        final List<ProductSkuDO> skus = productSkuService.selectListBySpuIdAndStatus(ProductSkuStatusEnum.ENABLE, Arrays.asList(spuId));
        log.info("查询上架状态的sku, spuId = {}, skus.size = {}", spuId, skus.size());
        if (CollUtil.isEmpty(skus)) {
            return;
        }

        final ProductSpuDO spu = getSpu(spuId);

        initSpuFromSkus(spuId, spu, skus);
    }

    @Override
    public void initSpuFromSkus(Long spuId, ProductSpuDO spu, List<ProductSkuDO> skus) {
        // sku 单价最低的商品的价格
        spu.setPrice(getMinValue(skus, ProductSkuDO::getPrice));
        // sku 单价最低的商品的市场价格
        spu.setMarketPrice(getMinValue(skus.stream().filter(v -> v.getMarketPrice() != null).collect(Collectors.toList()), ProductSkuDO::getMarketPrice));
        // sku 单价最低的商品的成本价格
        spu.setCostPrice(getMinValue(skus.stream().filter(v -> v.getCostPrice() != null).collect(Collectors.toList()), ProductSkuDO::getCostPrice));
        // skus 库存总数
        spu.setStock(getSumValue(skus, ProductSkuDO::getStock, Integer::sum));
        if (spu.getStock() > ProductConstant.STOCK_MAX) {
            spu.setStock(ProductConstant.STOCK_MAX);
        }

        productSpuMapper.updateById(spu);
        log.info("spu更新价格, spuId = {}, price = {}", spuId, spu.getPrice());
    }

    /**
     * 校验商品分类是否合法
     *
     * @param id 商品分类编号
     */
    private void validateCategory(Long id) {
        categoryService.validateCategory(id);
        // 校验层级
        if (categoryService.getCategoryLevel(id) < CATEGORY_LEVEL) {
            throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR);
        }
    }

    @Override
    public List<ProductSpuDO> validateSpuList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        // 获得商品信息
        List<ProductSpuDO> list = productSpuMapper.selectBatchIds(ids);
        Map<Long, ProductSpuDO> spuMap = CollectionUtils.convertMap(list, ProductSpuDO::getId);
        // 校验
        ids.forEach(id -> {
            ProductSpuDO spu = spuMap.get(id);
            if (spu == null) {
                throw exception(SPU_NOT_EXISTS);
            }
            if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
                throw exception(SPU_NOT_ENABLE, spu.getName());
            }
        });
        return list;
    }

    @Override
    public void updateBrowseCount(Long id, int incrCount) {
        productSpuMapper.updateBrowseCount(id, incrCount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSpu(Long id) {
        // 校验存在
        validateSpuExists(id);
        // 校验商品状态不是回收站不能删除
        ProductSpuDO spuDO = productSpuMapper.selectById(id);
        // 判断 SPU 状态是否为回收站
        if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) {
            throw exception(SPU_NOT_RECYCLE);
        }
        // TODO 芋艿：【可选】参与活动中的商品，不允许删除？？？

        // 删除 SPU
        productSpuMapper.deleteById(id);
        // 删除关联的 SKU
        productSkuService.deleteSkuBySpuId(id);
    }

    private void validateSpuExists(Long id) {
        if (productSpuMapper.selectById(id) == null) {
            throw exception(SPU_NOT_EXISTS);
        }
    }

    @Override
    public ProductSpuDO getSpu(Long id) {
        return productSpuMapper.selectById(id);
    }

    @Override
    public List<ProductSpuDO> getSpuList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return productSpuMapper.selectBatchIds(ids);
    }

    @Override
    public List<ProductSpuDO> getSpuListByCategoryIds(Collection<Long> categoryIds) {
        if (CollUtil.isEmpty(categoryIds)) {
            return Collections.emptyList();
        }
        return productSpuMapper.getSpuListByCategoryIds(categoryIds);
    }

    @Override
    public List<ProductSpuDO> getSpuListByStatus(Integer status) {
        return productSpuMapper.selectList(ProductSpuDO::getStatus, status);
    }

    @Override
    public PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
        return productSpuMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO) {
        // 查找时，如果查找某个分类编号，则包含它的子分类。因为顶级分类不包含商品
        Set<Long> categoryIds = new HashSet<>();
        if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) {
            categoryIds.add(pageReqVO.getCategoryId());
            List<ProductCategoryDO> categoryChildren = categoryService.getCategoryList(new ProductCategoryListReqVO()
                    .setStatus(CommonStatusEnum.ENABLE.getStatus()).setParentId(pageReqVO.getCategoryId()));
            categoryIds.addAll(convertList(categoryChildren, ProductCategoryDO::getId));
        }
        if (CollUtil.isNotEmpty(pageReqVO.getCategoryIds())) {
            categoryIds.addAll(pageReqVO.getCategoryIds());
            List<ProductCategoryDO> categoryChildren = categoryService.getCategoryList(new ProductCategoryListReqVO()
                    .setStatus(CommonStatusEnum.ENABLE.getStatus()).setParentIds(pageReqVO.getCategoryIds()));
            categoryIds.addAll(convertList(categoryChildren, ProductCategoryDO::getId));
        }
        // 分页查询
        return productSpuMapper.selectPage(pageReqVO, categoryIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpuStock(Map<Long, Integer> stockIncrCounts) {
        stockIncrCounts.forEach((id, incCount) -> productSpuMapper.updateStock(id, incCount));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO) {
        // 校验存在
        validateSpuExists(updateReqVO.getId());
        // TODO 芋艿：【可选】参与活动中的商品，不允许下架？？？

        final boolean isEnable = ProductSpuStatusEnum.isEnable(updateReqVO.getStatus());
        if (isEnable) {
            final List<ProductSkuDO> productSkuDOS = productSkuService.selectListBySpuIdAndStatus(ProductSkuStatusEnum.ENABLE,
                    Arrays.asList(updateReqVO.getId()));
            if (CollUtil.isEmpty(productSkuDOS)) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.SPU_FIELD_DEFAULT_ERROR, "不能上架商品，没有上架状态的SKU");
            }
        }

        // 更新状态
        ProductSpuDO productSpuDO = productSpuMapper.selectById(updateReqVO.getId()).setStatus(updateReqVO.getStatus());
        productSpuMapper.updateById(productSpuDO);
    }

    @Override
    public Map<Integer, Long> getTabsCount() {
        Map<Integer, Long> counts = Maps.newLinkedHashMapWithExpectedSize(5);
        // 查询销售中的商品数量
        counts.put(ProductSpuPageReqVO.FOR_SALE,
                productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()));
        // 查询仓库中的商品数量
        counts.put(ProductSpuPageReqVO.IN_WAREHOUSE,
                productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.DISABLE.getStatus()));
        // 查询售空的商品数量
        counts.put(ProductSpuPageReqVO.SOLD_OUT,
                productSpuMapper.selectCount(ProductSpuDO::getStock, 0));
        // 查询触发警戒库存的商品数量
        counts.put(ProductSpuPageReqVO.ALERT_STOCK,
                productSpuMapper.selectCount());
        // 查询回收站中的商品数量
        counts.put(ProductSpuPageReqVO.RECYCLE_BIN,
                productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()));
        return counts;
    }

    @Override
    public Long getSpuCountByCategoryId(Long categoryId) {
        return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, categoryId);
    }

    // ========== 新增 =========

    // 插入属性值
    private void insertPropertyValue(Long spuId, ProductSpuSaveReqVO updateReqVO) {
        // 1.插入spu属性值
        insertSpuPropertyValue(spuId, updateReqVO);

        // 2.插入sku属性值
        insertSkuPropertyValue(spuId);
    }

    private void insertSpuPropertyValue(Long spuId, ProductSpuSaveReqVO updateReqVO) {
        if (CollUtil.isEmpty(updateReqVO.getProperties())) {
            return;
        }

        // 查询已存在的value
        final List<ProductPropertyValueDO> existedValueList = productPropertyValueService.getPropertyValueListBySpuId(PropertyValueTypeEnum.SPU,
                Collections.singleton(spuId));
        final Map<String, ProductPropertyValueDO> existedValueMap = convertMap(existedValueList, p -> p.getPropertyId() + p.getName());
        final List<String> existedValues = existedValueList.stream().map(v -> v.getPropertyId() + ":" + v.getName()).collect(Collectors.toList());
        log.info("spu属性值-查询已存在的value, spuId = {}, existedValues = {}", spuId, existedValues);

        for (ProductSpuSaveReqVO.Property property : updateReqVO.getProperties()) {
            // 存储属性值
            final ProductPropertyValueSaveReqVO createReqVO = createSpuPropertyValue(spuId, property);
            productPropertyValueService.createPropertyValue(PropertyValueTypeEnum.SPU, createReqVO);

            existedValueMap.remove(property.getPropertyId() + property.getValueName());
        }

        if (CollUtil.isNotEmpty(existedValueMap)) {
            // 删除不存在的value
            final Collection<Long> propertyValueIds = existedValueMap.values().stream().map(v -> v.getId()).collect(Collectors.toSet());
            final List<String> propertyValues = existedValueMap.values().stream().map(v -> v.getPropertyId() + ":" + v.getName()).collect(Collectors.toList());
            log.info("spu属性值-删除不存在的value, spuId = {}, propertyValueIds = {}, propertyValues = {}",
                    spuId, propertyValueIds, propertyValues);
            productPropertyValueService.deleteBatchIds(propertyValueIds);
        }
    }

    private static ProductPropertyValueSaveReqVO createSpuPropertyValue(Long spuId, ProductSpuSaveReqVO.Property property) {
        final ProductPropertyValueSaveReqVO createReqVO = new ProductPropertyValueSaveReqVO();
        createReqVO.setPropertyId(property.getPropertyId());
        createReqVO.setName(property.getValueName());
        createReqVO.setStructuredValue(property.getStructuredValue());
        createReqVO.setRemark(property.getRemark());
        createReqVO.setSpuId(spuId);
        return createReqVO;
    }

    private void insertSkuPropertyValue(Long spuId) {
        // 查询sku
        List<ProductSkuDO> skus = productSkuService.getSkuListBySpuIdWithPropertyJson(spuId);
        log.info("sku属性值-查询sku, spuId = {}, skus.size = {}", spuId, skus.size());

        // 查询spu下所有的sku的属性值
        final List<ProductPropertyValueDO> existedPropertyValueList = productPropertyValueService.getPropertyValueListBySpuId(PropertyValueTypeEnum.SKU,
                Arrays.asList(spuId));
        final Map<Long, List<ProductPropertyValueDO>> skuPropertyValueMap =
                existedPropertyValueList.stream().collect(Collectors.groupingBy(ProductPropertyValueDO::getSkuId));
        final Map<String, ProductPropertyValueDO> existedValueMap = convertMap(existedPropertyValueList, p -> p.getSkuId() + p.getPropertyId() + p.getName());

        // 遍历sku，单独存储属性值
        int valueIdNullCount = 0;
        for (ProductSkuDO sku : skus) {
            // 获取sku的属性值
            final List<ProductPropertyValueDO> skuPropertyValueList = skuPropertyValueMap.getOrDefault(sku.getId(), new ArrayList<>());
            final List<String> existedValues = skuPropertyValueList.stream().map(v -> v.getPropertyId() + ":" + v.getName()).collect(Collectors.toList());
            log.info("sku属性值-查询已存在的value, skuId = {}, existedValues = {}", sku.getId(), existedValues);

            final List<ProductSkuDO.Property> properties = sku.getProperties();
            if (CollUtil.isNotEmpty(properties)) {
                for (ProductSkuDO.Property property : properties) {
                    // 存储属性值
                    final ProductPropertyValueSaveReqVO createReqVO = createSkuPropertyValue(spuId, sku, property);
                    Long valueId = productPropertyValueService.createPropertyValue(PropertyValueTypeEnum.SKU, createReqVO);

                    existedValueMap.remove(sku.getId() + property.getPropertyId() + property.getValueName());
                    if (property.getValueId() == null) {
                        property.setValueId(valueId);
                        valueIdNullCount++;
                    }
                }
            }
        }

        if (CollUtil.isNotEmpty(existedValueMap)) {
            // 删除不存在的value
            final Collection<ProductPropertyValueDO> deletePropertyValueList = existedValueMap.values();
            final Collection<Long> propertyValueIds = deletePropertyValueList.stream().map(v -> v.getId()).collect(Collectors.toSet());
            final List<String> propertyValues =
                    deletePropertyValueList.stream().map(v -> v.getSkuId() + "->" + v.getPropertyId() + ":" + v.getName()).collect(Collectors.toList());
            log.info("sku属性值-删除不存在的value, spuId = {}, propertyValueIds = {}, propertyValues = {}",
                    spuId, propertyValueIds, propertyValues);
            productPropertyValueService.deleteBatchIds(propertyValueIds);
        }

        if (valueIdNullCount > 0) {
            // 更新sku
            log.info("sku属性值-更新sku, spuId = {}, valueIdNullCount = {}", spuId, valueIdNullCount);
            productSkuService.updateSkuList(skus);
        }
    }

    private static ProductPropertyValueSaveReqVO createSkuPropertyValue(Long spuId, ProductSkuDO sku, ProductSkuDO.Property property) {
        final ProductPropertyValueSaveReqVO createReqVO = new ProductPropertyValueSaveReqVO();
        createReqVO.setPropertyId(property.getPropertyId());
        createReqVO.setName(property.getValueName());
        createReqVO.setStructuredValue(property.getStructuredValue());
        createReqVO.setRemark(property.getRemark());
        createReqVO.setSpuId(spuId);
        createReqVO.setSkuId(sku.getId());
        return createReqVO;
    }

    /**
     * 按照商品名称搜索
     *
     * @param reqVO
     * @return
     */
    @Override
    public PageResult<ProductSpuDO> selectPageByLikeName(AppProductSpuPageLikeNameReqVO reqVO) {
        return productSpuMapper.selectPageByLikeName(reqVO);
    }

    @Override
    public <T extends AppDenominationVO> void setAppDenominationVO(List<T> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }

        final List<Long> spuIds = list.stream().map(v -> v.getSpuId()).collect(Collectors.toList());
        final Map<Long, SkuDiscountDTO> maxDiscountSpuMap = productSkuService.getMaxDiscountSkuBySpuIds(spuIds);
        log.info("查询最大折扣的sku，maxDiscountSpuMap = {}", JsonUtils.toJsonString(maxDiscountSpuMap));
        if (CollUtil.isEmpty(maxDiscountSpuMap)) {
            return;
        }

        for (T spu : list) {
            final Long spuId = spu.getSpuId();
            final SkuDiscountDTO maxDiscountSku = maxDiscountSpuMap.get(spuId);
            if (maxDiscountSku == null) {
                log.warn("查询不到spu下折扣最大的sku, spuId = {}", spuId);
                continue;
            }

            // 支付货币
            final String paymentCurrency = exchangeRateApi.getPaymentCurrency();
            spu.setPaymentCurrency(paymentCurrency);

            // 面值
            spu.setMinDenomination(maxDiscountSku.getMinDenomination());
            spu.setMaxDenomination(maxDiscountSku.getMaxDenomination());

            if (maxDiscountSku.getMinDenomination().equals(maxDiscountSku.getMaxDenomination())) {
                // 固定面值

                // 面值价格
                spu.setMinDenominationCardPrice(maxDiscountSku.getPrice());
                spu.setMaxDenominationCardPrice(maxDiscountSku.getPrice());

                // 支付价格
                spu.setMinDenominationPaymentPrice(exchangeRateApi.calculateWithCurrency(maxDiscountSku.getPrice(), spu.getCardCurrencyCode()));
                spu.setMaxDenominationPaymentPrice(exchangeRateApi.calculateWithCurrency(maxDiscountSku.getPrice(), spu.getCardCurrencyCode()));

                if (maxDiscountSku.getCombinationPrice() != null) {
                    // 团购面值价格
                    spu.setMinDenominationCombinationCardPrice(maxDiscountSku.getCombinationPrice());
                    spu.setMaxDenominationCombinationCardPrice(maxDiscountSku.getCombinationPrice());

                    // 团购支付价格
                    final Integer combinationPaymentPrice = exchangeRateApi.calculateWithCurrency(
                            maxDiscountSku.getCombinationPrice(), maxDiscountSku.getCombinationCurrencyCode());
                    spu.setMinDenominationCombinationPaymentPrice(combinationPaymentPrice);
                    spu.setMaxDenominationCombinationPaymentPrice(combinationPaymentPrice);
                }
            } else {
                // 自定义面值
                spu.setMinDenominationCardPrice((maxDiscountSku.getMinDenomination() / 100) * maxDiscountSku.getPrice());
                spu.setMaxDenominationCardPrice((maxDiscountSku.getMaxDenomination() / 100) * maxDiscountSku.getPrice());

                // 支付价格
                spu.setMinDenominationPaymentPrice(exchangeRateApi.calculateWithCurrency(spu.getMinDenominationCardPrice(), spu.getCardCurrencyCode()));
                spu.setMaxDenominationPaymentPrice(exchangeRateApi.calculateWithCurrency(spu.getMaxDenominationCardPrice(), spu.getCardCurrencyCode()));

                if (maxDiscountSku.getCombinationPrice() != null) {
                    // 团购面值价格
                    spu.setMinDenominationCombinationCardPrice((maxDiscountSku.getMinDenomination() / 100) * maxDiscountSku.getCombinationPrice());
                    spu.setMaxDenominationCombinationCardPrice((maxDiscountSku.getMaxDenomination() / 100) * maxDiscountSku.getCombinationPrice());

                    // 团购支付价格
                    spu.setMinDenominationCombinationPaymentPrice(exchangeRateApi.calculateWithCurrency(
                            spu.getMinDenominationCombinationCardPrice(), maxDiscountSku.getCombinationCurrencyCode()));
                    spu.setMaxDenominationCombinationPaymentPrice(exchangeRateApi.calculateWithCurrency(
                            spu.getMaxDenominationCombinationCardPrice(), maxDiscountSku.getCombinationCurrencyCode()));
                }
            }

            // 设置折扣率
            final BigDecimal discountRate = maxDiscountSku.getDiscountRate() != null ? maxDiscountSku.getDiscountRate().setScale(2, BigDecimal.ROUND_HALF_UP) : new BigDecimal(100);
            spu.setDiscountRate(discountRate.stripTrailingZeros().toPlainString());
        }
    }

    @Deprecated
    private  <T extends AppDenominationVO> void setAppDenominationVO_old(List<T> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }

        final List<Long> spuIds = list.stream().map(v -> v.getSpuId()).collect(Collectors.toList());
        final List<ProductSkuDenominationDO> minDenominationSkuList = productSkuService.selectMinDenominationSkuBySpuIds(spuIds);
        if (CollUtil.isEmpty(minDenominationSkuList)) {
            return;
        }
        // 将denominationList转换为map，key为spuId
        final Map<Long, ProductSkuDenominationDO> denominationMap = minDenominationSkuList.stream()
                .collect(Collectors.toMap(ProductSkuDenominationDO::getSpuId, v -> v, (existing, replacement) -> existing));

        final List<Long> minDenominationSkuIds = minDenominationSkuList.stream().map(v -> v.getSkuId()).collect(Collectors.toList());
        final List<CombinationProductDTO> combinationProducts = combinationActivityApi.getCombinationProductBySkuIds(minDenominationSkuIds);
        final Map<Long, CombinationProductDTO> combinationSkuMap = combinationProducts.stream()
                .collect(Collectors.toMap(CombinationProductDTO::getSkuId, v -> v, (existing, replacement) -> existing));

        for (T t : list) {
            final Long spuId = t.getSpuId();
            final ProductSkuDenominationDO denomination = denominationMap.get(spuId);
            if (denomination == null) {
                log.warn("查询不到spu下sku的最小面值, spuId = {}", spuId);
                continue;
            }

            final CombinationProductDTO combinationSku = combinationSkuMap.get(denomination.getSkuId());

            // 支付货币
            final String paymentCurrency = exchangeRateApi.getPaymentCurrency();
            t.setPaymentCurrency(paymentCurrency);

            // 面值
            t.setMinDenomination(denomination.getMinDenomination());
            t.setMaxDenomination(denomination.getMaxDenomination());

            if (denomination.getMinDenomination().equals(denomination.getMaxDenomination())) {
                // 固定面值

                // 面值价格
                t.setMinDenominationCardPrice(denomination.getPrice());
                t.setMaxDenominationCardPrice(denomination.getPrice());

                // 支付价格
                final Integer paymentPrice = exchangeRateApi.calculateWithCurrency(denomination.getPrice(), t.getCardCurrencyCode());
                t.setMinDenominationPaymentPrice(paymentPrice);
                t.setMaxDenominationPaymentPrice(paymentPrice);

                if (combinationSku != null) {
                    // 团购面值价格
                    t.setMinDenominationCombinationCardPrice(combinationSku.getCombinationPrice());
                    t.setMaxDenominationCombinationCardPrice(combinationSku.getCombinationPrice());

                    // 团购支付价格
                    final Integer combinationPaymentPrice = exchangeRateApi.calculateWithCurrency(
                            combinationSku.getCombinationPrice(), combinationSku.getCurrencyCode());
                    t.setMinDenominationCombinationPaymentPrice(combinationPaymentPrice);
                    t.setMaxDenominationCombinationPaymentPrice(combinationPaymentPrice);
                }
            } else {
                // 面值
                t.setMinDenominationCardPrice(denomination.getMinDenomination() * denomination.getPrice());
                t.setMaxDenominationCardPrice(denomination.getMaxDenomination() * denomination.getPrice());

                // 支付价格
                t.setMinDenominationPaymentPrice(exchangeRateApi.calculateWithCurrency(t.getMinDenominationCardPrice(), t.getCardCurrencyCode()));
                t.setMaxDenominationPaymentPrice(exchangeRateApi.calculateWithCurrency(t.getMaxDenominationCardPrice(), t.getCardCurrencyCode()));

                if (combinationSku != null) {
                    // 团购面值价格
                    t.setMinDenominationCombinationCardPrice(denomination.getMinDenomination() * combinationSku.getCombinationPrice());
                    t.setMaxDenominationCombinationCardPrice(denomination.getMaxDenomination() * combinationSku.getCombinationPrice());

                    // 团购支付价格
                    t.setMinDenominationCombinationPaymentPrice(exchangeRateApi.calculateWithCurrency(
                            t.getMinDenominationCombinationCardPrice(), combinationSku.getCurrencyCode()));
                    t.setMaxDenominationCombinationPaymentPrice(exchangeRateApi.calculateWithCurrency(
                            t.getMaxDenominationCombinationCardPrice(), combinationSku.getCurrencyCode()));
                }
            }

            // 设置折扣率
            final BigDecimal discountRate;
            if (combinationSku != null) {
                discountRate = new BigDecimal(t.getMinDenominationCombinationCardPrice())
                        .divide(new BigDecimal(t.getMinDenomination()), 2, BigDecimal.ROUND_HALF_UP);
            } else {
                discountRate = new BigDecimal(t.getMinDenominationCardPrice())
                        .divide(new BigDecimal(t.getMinDenomination()), 2, BigDecimal.ROUND_HALF_UP);
            }
            t.setDiscountRate(discountRate.toPlainString());
        }
    }

}
